// Copyright (C) 2009 Jesse Jones
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using MmmDoc;
using MmmDoc.Database;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace MmmDoc.Html
{
	/// <summary>Generates a table for each namespace with the rows containing the types within that namespace.</summary>
	internal sealed class GenerateNamespacesFile : WriteNormalHtml
	{
		public GenerateNamespacesFile(Document doc) : base("namespaces-file.html", "namespaces-file.css")
		{
			m_doc = doc;
			
			foreach (TypeDef type in m_doc.Types)
			{
				List<TypeDef> types;
				if (!m_namespaces.TryGetValue(type.Namespace, out types))
				{
					types = new List<TypeDef>();
					m_namespaces.Add(type.Namespace, types);
				}
				
				types.Add(type);
			}
		}
		
		public string[] Namespaces
		{
			get {return m_namespaces.Keys.ToArray();}
		}
		
		#region Protected Methods
		protected override string OnTitle
		{
			get {return "Namespaces";}
		}
		
		protected override void OnWriteBodyContents(Writer writer)
		{
			foreach (KeyValuePair<string, List<TypeDef>> entry in m_namespaces)
			{
				if (string.IsNullOrEmpty(entry.Key))
					writer.WriteStartTagLine("TABLE", "width", "100%", "id", "Globals");
				else
					writer.WriteStartTagLine("TABLE", "width", "100%", "id", entry.Key);
					
					writer.WriteStartTagLine("CAPTION");
					if (string.IsNullOrEmpty(entry.Key))
						writer.WriteElementLine("SPAN", "Global Namespace", "class", "namespace-name");
					else
						writer.WriteElementLine("SPAN", entry.Key + " Namespace", "class", "namespace-name");
					TypeDef ntype = DoFindNamespaceDoc(entry.Key);
					if (ntype != null)
					{
						writer.WriteElementLine("BR", null, "class", "namespace-sep");
						DoWriteBody(writer, ntype);
					}
					writer.WriteEndTagLine("CAPTION");
					
					writer.WriteStartTagLine("COLGROUP");
						writer.WriteElementLine("COL", null, "class", "type");
						writer.WriteElementLine("COL", null, "class", "description");
					writer.WriteEndTagLine("COLGROUP");
					
					writer.WriteStartTagLine("THEAD");
						writer.WriteStartTagLine("TR");
							writer.WriteElementLine("TD", "Type", "class", "type");
							writer.WriteElementLine("TD", "Description", "class", "description");
						writer.WriteEndTagLine("TR");
					writer.WriteEndTagLine("THEAD");
					
					writer.WriteStartTagLine("TBODY");
						entry.Value.Sort((lhs, rhs) => lhs.Name.CompareTo(rhs.Name));
						
						foreach (TypeDef type in entry.Value)
						{
							if (!type.IsExcluded())
							{
								writer.WriteStartTagLine("TR");
									writer.WriteStartTag("TD");
										writer.WriteElement("A", type.Name, "href", "types/" + type.FileName() + ".html", "target", "_top", "class", "type");
									writer.WriteEndTag("TD");
									writer.WriteLine();
									
									DoWriteSummary(writer, type);
								writer.WriteEndTagLine("TR");
							}
						}
					writer.WriteEndTagLine("TBODY");
				writer.WriteEndTagLine("TABLE");
				
				writer.WriteElementLine("P", null);
			}
		}
		#endregion
	
		#region Private Methods
		private void DoWriteSummary(Writer writer, TypeDef type)
		{
			if (type.Definition != null && type.Definition.Summary != null)
			{
				writer.WriteStartTag("TD");
					DoWriteBody(writer, type);
				writer.WriteEndTag("TD");
				writer.WriteLine();
			}
			else
			{
				writer.WriteElementLine("TD", null);
			}
		}
		
		private void DoWriteBody(Writer writer, TypeDef type)
		{
			writer.WriteStartTag("SPAN", "class", "description");
			WriteMarkup.Invoke(writer, type.Definition.Summary, false, null);
			writer.WriteEndTag("SPAN");
		}
		
		private TypeDef DoFindNamespaceDoc(string ns)
		{
			return m_doc.Types.SingleOrDefault(t => t.Namespace == ns && t.Name == "NamespaceDoc");
		}
		#endregion
		
		#region Fields
		private Document m_doc;
		private SortedDictionary<string, List<TypeDef>> m_namespaces = new SortedDictionary<string, List<TypeDef>>();
		#endregion
	}
}
